<?php

namespace Main\Composite;

class Client
{
    public static function main()
    {
        $root = self::createObjectTree();

        $files = $root->getDirectoryFiles();
        var_dump($files);
    }

    protected static function createObjectTree($root = null, string $dir = '')
    {
        if (is_null($root)) {
            $root = new Directory();
            $dir = __DIR__ . '/..';
        }
        $resource = opendir($dir);
        while (false !== $file = readdir($resource)) {
            if (in_array($file, ['.', '..'])) {
                continue;
            }
            $file = realpath($dir . DIRECTORY_SEPARATOR . $file);
            if (is_dir($file)) {
                $component = new Directory();
                self::createObjectTree($component, $file);
            } else {
                $component = new File($file);
            }
            $root->add($component);
        }
        closedir($resource);
        return $root;
    }
}

interface Component
{
    public function add(Component $component): void;
    public function remove(Component $component): void;
    public function getChild(int $i): Component;
    public function getDirectoryFiles(): array;
}

class Directory implements Component
{
    /**
     * @var Component[]
     */
    protected array $children = [];

    public function add(Component $component): void
    {
        $this->children[] = $component;
    }

    public function remove(Component $component): void
    {
        $index = array_search($component, $this->children, true);
        if (false !== $index) {
            array_splice($this->children, $index, 1);
        }
    }

    public function getChild(int $i): Component
    {
        return $this->children[$i];
    }

    public function getDirectoryFiles(): array
    {
        $directories = [];
        foreach ($this->children as $child) {
            $directories = array_merge($directories, $child->getDirectoryFiles());
        }
        return $directories;
    }
}

class File implements Component
{
    protected string $name = '';

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function add(Component $component): void
    {
    }

    public function remove(Component $component): void
    {
    }

    public function getChild(int $i): Component
    {
        return null;
    }

    public function getDirectoryFiles(): array
    {
        return [$this->name];
    }
}


Client::main();
